/**
 * 所有捕获器都可以访问相应的参数，基于这些参数可以重建被捕获方法的原始行为。比如，get() 捕获器会接收到目标对象、要查询的属性和代理对象三个参数。
 */
;(function () {
    const target = {
        foo: 'bar'
    };
    const handler = {
        get(trapTarget, property, receiver) {
            console.log(trapTarget === target); // true
            console.log(property);  // foo
            console.log(receiver === proxy); // true
        }
    };
    const proxy = new Proxy(target, handler);
    proxy.foo;
})()


/**
 * 有了这些参数，就可以重建被捕获方法的原始行为
 */
;(function () {
    const target = {
        foo: 'bar'
    };
    const handler = {
        get(trapTarget, property, receiver) {
            return trapTarget[property];
        }
    };
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); // bar
    console.log(target.foo); // bar
})()

/**
 * 可以通过调用全局 Reflect 对象上（封装了原始行为）的同名方法来轻松重建。
 */
;(function () {
    const target = {
        foo: 'bar'
    };
    const handler = {
        get() {
            return Reflect.get(...arguments);
        }
    };
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); // bar
    console.log(target.foo); // bar
})()

/**
 * 如果真想创建一个可以捕获所有方法，然后将每个方法转发给对应反射 API 的空代理，那么甚至不需要定义处理程序对象
 */
;(function () {
    const target = {
        foo: 'bar'
    };
    const proxy = new Proxy(target, Reflect);
    console.log(proxy.foo); // bar
    console.log(target.foo); // bar
})()

/**
 * 反射 API 为开发者准备好了样板代码，在此基础上开发者可以用最少的代码修改捕获的方法。比如，下面的代码在某个属性被访问时，会对返回的值进行一番修饰
 */
;(function () {
    const target = {
        foo: 'bar',
        baz: 'qux'
    };
    const handler = {
        get(trapTarget, property, receiver) {
            let decoration = '';
            if (property === 'foo') {
                decoration = '!!!';
            }
            return Reflect.get(...arguments) + decoration;
        }
    };
    const proxy = new Proxy(target, handler);
    console.log(proxy.foo); // bar!!!
    console.log(target.foo); // bar
    console.log(proxy.baz); // qux
    console.log(target.baz); // qux
})()
